import { useEffect, useRef } from "react";
import NERTC from "nertc-web-sdk";

import './LiveCourse.css';

function LiveCourse() {
  const videoViewRefs = useRef([]);

  const searchParams = new URLSearchParams(window.location.search);
  const trainerId = parseInt(searchParams.get('tid'));
  let isTrainer = false;

  const streamContainers = [
    { index: 0, stream: null, usedBy: null, mute: false },
    { index: 1, stream: null, usedBy: null, mute: true },
    { index: 2, stream: null, usedBy: null, mute: true },
    { index: 3, stream: null, usedBy: null, mute: true },
  ];

  const channelName = 'live-course-01';
  let localUid = null;
  let client = null;
  let localStream = null;

  function initUid() {
    let uid = searchParams.get('uid') || localStorage.getItem('live-course-uid');
    if (!uid) {
      uid = Math.ceil(Math.random() * 1e5 + 10) + '';
      localStorage.setItem('live-course-uid', uid);
    }
    localUid = parseInt(uid);
    isTrainer = trainerId === localUid;
  }

  function getContainerFor(uid) {
    let container = streamContainers.find(it => it.usedBy === uid);
    if (container) {
      return videoViewRefs.current[container.index];
    }

    if (uid === localUid) {
      // 本地流
      if (isTrainer) {
        // 自己是教练
        container = streamContainers.find(it => it.index === 0 && it.usedBy === null);
      } else {
        // 自己是学员
        container = streamContainers.find(it => it.index === 1 && it.usedBy === null);
      }
    } else {
      // 远端流
      const minIndex = isTrainer ? 1 : 2;
      if (uid === trainerId) {
        // 对方是教练
        container = streamContainers.find(it => it.index === 0 && it.usedBy === null);
      } else {
        container = streamContainers.find(it => it.index >= minIndex && it.usedBy === null);
      }
    }

    if (container) {
      container.usedBy = uid;
      return container;
    }
  }

  function releaseContainerOf(uid) {
    console.warn('release uid', uid);
    let container = streamContainers.find(it => it.usedBy === uid);
    if (container) {
      container.usedBy = null;
    }
  }

  async function publish() {
    console.warn('开始发布视频流');
    // 发布本地媒体给房间对端
    try {
      await client.publish(localStream)
      console.warn('本地 publish 成功');
    } catch (err) {
      console.error('本地 publish 失败: ', err);
    }
  }

  async function subscribe(remoteStream) {
    remoteStream.setSubscribeConfig({
      audio: true,
      video: true,
    });

    try {
      await client.subscribe(remoteStream)
      console.warn('本地 subscribe 成功');
    } catch (err) {
      console.warn('本地 subscribe 失败: ', err);
    }
  }

  async function initLocalStream() {
    // 初始化本地的Stream实例，用于管理本端的音视频流
    localStream = NERTC.createStream({
      uid: localUid,
      audio: true, // 是否启动mic
      video: true, // 是否启动camera
      screen: false, // 是否启动屏幕共享
    });
    // 设置本地视频质量
    localStream.setVideoProfile({
      resolution: NERTC.VIDEO_QUALITY_720p, //设置视频分辨率
      frameRate: NERTC.CHAT_VIDEO_FRAME_RATE_25, //设置视频帧率
    });
    // 设置本地音频质量
    localStream.setAudioProfile('speech_low_quality');
    // 启动媒体，打开实例对象中设置的媒体设备
    try {
      await localStream.init();
      console.warn('音视频开启完成，可以播放了');

      const container = getContainerFor(localUid);
      if (!container) {
        console.warn('没有空位');
      }
      container.stream = localStream;
      const div = videoViewRefs.current[container.index];
      localStream.play(div);
      localStream.setLocalRenderMode({
        // 设置视频窗口大小
        width: div.clientWidth,
        height: div.clientHeight,
        cut: false, // 是否裁剪
      });
      // 发布
      await publish();
    } catch (err) {
      console.warn('音视频初始化失败: ', err);
      localStream = null;
    }
  }

  async function joinChannel(token) {
    if (!client) {
      return;
    }
    console.info('开始加入房间: ', channelName);
    try {
      await client.join({
        channelName,
        uid: localUid,
        token,
      })
      console.info('加入房间成功，开始初始化本地音视频流');
      await initLocalStream();
    } catch (err) {
      console.error('加入房间失败：', err);
    }
  }

  function initClient() {
    client = NERTC.createClient({
      appkey: 'd3c208518c3d0764ca7cfb6a5953829e',
      debug: true,
    });

    client.on('peer-online', (evt) => {
      console.warn(`${evt.uid} 加入房间`);
    });

    client.on('peer-leave', (evt) => {
      console.warn(`${evt.uid} 离开房间`);
      releaseContainerOf(evt.uid);
    });

    client.on('stream-added', async (evt) => {
      const stream = evt.stream;
      await subscribe(stream);
    });

    client.on('stream-removed', (evt) => {
      const stream = evt.stream
      const userId = stream.getId()
      stream.stop();
      console.warn('远端流停止订阅，需要更新', userId, stream)
    });

    client.on('stream-subscribed', async (evt) => {
      console.warn('收到了对端的流，准备播放');
      const remoteStream = evt.stream;
      // 用于播放对方视频画面的div节点
      const container = getContainerFor(remoteStream.getId());
      if (!container) {
        console.warn('没有可用的播放位');
        return;
      }

      try {
        const div = videoViewRefs.current[container.index]
        await remoteStream.play(div);
        console.warn('播放视频');

        container.stream = remoteStream;
        remoteStream.setRemoteRenderMode({
          // 设置视频窗口大小
          width: div.clientWidth,
          height: div.clientHeight,
          cut: false, // 是否裁剪
        });
      } catch (err) {
        console.warn('播放对方视频失败了: ', err);
      }
    });

    client.on('NotAllowedError', error => {
      const errorCode = error.getCode();
      if (errorCode === 41030) {
        // AUTO_PLAY_NOT_ALLOWED, 引导用户进行手势交互
        // 调用 stream.resume() 恢复音视频正常播放
      }
    });
  }

  useEffect(() => {
    async function init() {
      initUid();
      initClient();
      await joinChannel();
    }

    init();
    // eslint-disable-next-line
  }, []);

  function toggleAudio(event, item) {
    if (item.stream) {
      if (item.mute) {
        item.mute = false;
        item.stream.setAudioVolume(100);
        event.target.className = 'mic';
      } else {
        item.mute = true;
        item.stream.setAudioVolume(0);
        event.target.className = 'mic-close';
      }
    }
  }

  return (
    <div className="live-course">
      <div className="video-views">
        {
          streamContainers.map((item) => (
            <div
              key={item.index}
              className="video-view"
              ref={
                (current) =>
                  videoViewRefs.current[item.index] = current
              }
            >
              <div className="control-tools">
                <div
                  className={item.mute ? 'mic-close' : 'mic'}
                  onClick={(e) => toggleAudio(e, item)}
                />
              </div>
            </div>
          ))
        }
      </div>
    </div>
  )
}

export default LiveCourse;
